通常大家剛接觸前端時,最先接觸的 css unit 都是 px
,但 px
作為一個絕對單位,在不同尺寸的瀏覽器視窗中所呈現的大小都是固定的,也因此催生了超多響應式網站的方案與討論,而我覺得 vw
可能是一個被低估的解決方案,接下來歡迎跟著我一起進到 vw
的美好世界。
vw
是什麼?在說明 vw
是什麼之前,先提另一個概念。
相信大家都知道 position: fixed
,當你為某個 DOM 設定為 fixed
後,該 DOM 如果使用 %
,他的計算基準就會基於你的視窗大小(不含佔位滾動條)。
程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: #041C29;
color: white;
}
.parent {
position: relative;
bottom: 0;
width: 30%;
height: 300px;
background-color: #E79C30;
}
.child {
width: 50%;
height: 100px;
bottom: 0;
}
.absolute {
position: absolute;
background-color: #A44542;
}
.fixed {
position: fixed;
background-color: #3E5B6D;
}
</style>
</head>
<body>
<div class="parent">
parent
<div class="child absolute">absolute</div>
<div class="child fixed">fixed</div>
</div>
</body>
</html>
結果
而 vw
其實就類似 fixed
時的百分比計算方式(請注意是類似而已),總結來說:
vw
是 Viewport Width
的縮寫1vw
= viewport width
的 1%程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
* {
margin: 0;
padding: 0;
}
body {
height: 200dvh;
}
.box {
font-size: 5vw;
width: 50vw;
}
.info {
font-size: 14px;
}
</style>
</head>
<body>
<div class="box">hi :)</div>
<div class="info"></div>
<script>
const domInfo = document.querySelector('.info')
const domBox = document.querySelector('.box')
const updateInfo = () => {
const style = getComputedStyle(domBox)
const fontSize = style.fontSize
const boxWidth = style.width
const viewportWidth = window.innerWidth
domInfo.innerHTML = `
<b>viewport width: ${viewportWidth}</b>
<p>
<b>font-size: ${fontSize}</b><br/>
(5 / 100) * ${viewportWidth} = ${5 / 100 * viewportWidth}
</p>
<p>
<b>width: ${boxWidth}</b><br/>
(50 / 100) * ${viewportWidth} = ${50 / 100 * viewportWidth}
</p>
`
}
window.addEventListener('resize', updateInfo)
window.addEventListener('DOMContentLoaded', updateInfo)
</script>
</body>
</html>
結果
從結果可以觀察到,視窗寬度變大時,那個 hi :)
也跟著變大了:
250px
時:
font-size: 5vw
的結果是 12.5px
,也就是視窗寬度的 5%
,也就是 250 * 5% = 12.5px
。width: 50vw
的結果是 125px
,也就是視窗寬度的 50%
,也就是 250 * 50% = 125px
。500px
時,font-size
值 ( 25px
) 跟 width
值 ( 250px
) 都直接乘以二。這就是 vw
的計算過程!明天我們將利用 vw
這個特性,介紹這個工作流的核心公式,希望你能理解並牢牢記得這個工作流的基石!
在技術文件中,更常見的專有名詞叫「視口」(Viewport)。
上面會不斷強調 vw
與 fixed + %
只是類似是因為:CSS 的 %
本質上是基於可排版空間的比例,而視窗如果遇到佔位滾動條,那剩餘的可排版空間其實就沒有整個視窗那麼大,而 vw
本質上完全就是視窗的比例,兩者基於的數值其實不太一樣。
程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<style>
* {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
height: 200dvh;
}
.w-full {
width: 100%;
}
.w-screen {
width: 100vw;
}
.box {
border: 2px solid black;
}
</style>
<div class="w-full box">100%</div>
<div class="w-screen box">100vw</div>
</body>
</html>
結果
後面會有一系列我遇過的問題以及我的解決方案,其中一篇就是滾動條問題,所以這邊就簡單聊一下我的看法。
因為 window 系統的瀏覽器都會有佔位的滾動條,導致實際可排版空間沒有完整的視窗這麼大,但是可以觀察一下上面 vw
的範例截圖,我刻意弄出滾動條來計算字體大小,即使出現滾動條,結果依然是基於包含滾動條的整個視窗寬度所計算出來的。
所以本質上這是排版問題而不是計算問題,實際上對於我的工作流來說影響非常小的,我總有一天也會分享我是如何緩解這個排版問題的,敬請期待~
為了文章的流暢,我們就都先不管那個滾動條了,以後再說吧~